{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "mS0bWISTqhMI",
    "outputId": "a6cbe1aa-ab9a-4d02-cc1c-d3e9514e8748"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using backend: pytorch\n",
      "/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.\n",
      "  import pandas.util.testing as tm\n"
     ]
    }
   ],
   "source": [
    "import dgl.nn as dglnn\n",
    "from dgl import from_networkx\n",
    "import torch.nn as nn\n",
    "import torch as th\n",
    "import torch.nn.functional as F\n",
    "import dgl.function as fn\n",
    "import networkx as nx\n",
    "import pandas as pd\n",
    "import socket\n",
    "import struct\n",
    "import random\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.model_selection import train_test_split\n",
    "import category_encoders as ce\n",
    "from sklearn.decomposition import PCA\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "ki0watiErdJp"
   },
   "outputs": [],
   "source": [
    "data = pd.read_csv('/content/NF-BoT-IoT.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 439
    },
    "id": "0JmyVopVrqWQ",
    "outputId": "7dd4b901-c0c4-4bb4-b5fa-d504fe9821f2"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>IPV4_SRC_ADDR</th>\n",
       "      <th>L4_SRC_PORT</th>\n",
       "      <th>IPV4_DST_ADDR</th>\n",
       "      <th>L4_DST_PORT</th>\n",
       "      <th>PROTOCOL</th>\n",
       "      <th>L7_PROTO</th>\n",
       "      <th>IN_BYTES</th>\n",
       "      <th>OUT_BYTES</th>\n",
       "      <th>IN_PKTS</th>\n",
       "      <th>OUT_PKTS</th>\n",
       "      <th>TCP_FLAGS</th>\n",
       "      <th>FLOW_DURATION_MILLISECONDS</th>\n",
       "      <th>Label</th>\n",
       "      <th>Attack</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>192.168.100.6</td>\n",
       "      <td>52670</td>\n",
       "      <td>192.168.100.1</td>\n",
       "      <td>53</td>\n",
       "      <td>17</td>\n",
       "      <td>5.212</td>\n",
       "      <td>71</td>\n",
       "      <td>126</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>4294966</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>192.168.100.6</td>\n",
       "      <td>49160</td>\n",
       "      <td>192.168.100.149</td>\n",
       "      <td>4444</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>217753000</td>\n",
       "      <td>199100</td>\n",
       "      <td>4521</td>\n",
       "      <td>4049</td>\n",
       "      <td>24</td>\n",
       "      <td>4176249</td>\n",
       "      <td>1</td>\n",
       "      <td>Theft</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>192.168.100.46</td>\n",
       "      <td>3456</td>\n",
       "      <td>192.168.100.5</td>\n",
       "      <td>80</td>\n",
       "      <td>17</td>\n",
       "      <td>0.000</td>\n",
       "      <td>8508021</td>\n",
       "      <td>8918372</td>\n",
       "      <td>9086</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>192.168.100.3</td>\n",
       "      <td>80</td>\n",
       "      <td>192.168.100.55</td>\n",
       "      <td>8080</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>8442138</td>\n",
       "      <td>9013406</td>\n",
       "      <td>9086</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>192.168.100.46</td>\n",
       "      <td>80</td>\n",
       "      <td>192.168.100.5</td>\n",
       "      <td>80</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>8374706</td>\n",
       "      <td>0</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600095</th>\n",
       "      <td>192.168.100.46</td>\n",
       "      <td>80</td>\n",
       "      <td>192.168.100.5</td>\n",
       "      <td>80</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>2330065</td>\n",
       "      <td>0</td>\n",
       "      <td>2523</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263037</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600096</th>\n",
       "      <td>192.168.100.5</td>\n",
       "      <td>0</td>\n",
       "      <td>192.168.100.3</td>\n",
       "      <td>0</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1054423</td>\n",
       "      <td>0</td>\n",
       "      <td>1513</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263062</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600097</th>\n",
       "      <td>192.168.100.7</td>\n",
       "      <td>365</td>\n",
       "      <td>192.168.100.3</td>\n",
       "      <td>565</td>\n",
       "      <td>17</td>\n",
       "      <td>0.000</td>\n",
       "      <td>62422</td>\n",
       "      <td>0</td>\n",
       "      <td>1357</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263062</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600098</th>\n",
       "      <td>192.168.100.3</td>\n",
       "      <td>50850</td>\n",
       "      <td>13.54.166.67</td>\n",
       "      <td>8883</td>\n",
       "      <td>6</td>\n",
       "      <td>222.178</td>\n",
       "      <td>11300</td>\n",
       "      <td>1664</td>\n",
       "      <td>32</td>\n",
       "      <td>32</td>\n",
       "      <td>24</td>\n",
       "      <td>4264935</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600099</th>\n",
       "      <td>192.168.100.6</td>\n",
       "      <td>49160</td>\n",
       "      <td>192.168.100.149</td>\n",
       "      <td>4444</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>40102320</td>\n",
       "      <td>37280</td>\n",
       "      <td>763</td>\n",
       "      <td>590</td>\n",
       "      <td>24</td>\n",
       "      <td>4270068</td>\n",
       "      <td>1</td>\n",
       "      <td>Theft</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>600100 rows × 14 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "         IPV4_SRC_ADDR  L4_SRC_PORT  ... Label  Attack\n",
       "0        192.168.100.6        52670  ...     0  Benign\n",
       "1        192.168.100.6        49160  ...     1   Theft\n",
       "2       192.168.100.46         3456  ...     0  Benign\n",
       "3        192.168.100.3           80  ...     0  Benign\n",
       "4       192.168.100.46           80  ...     0  Benign\n",
       "...                ...          ...  ...   ...     ...\n",
       "600095  192.168.100.46           80  ...     0  Benign\n",
       "600096   192.168.100.5            0  ...     0  Benign\n",
       "600097   192.168.100.7          365  ...     0  Benign\n",
       "600098   192.168.100.3        50850  ...     0  Benign\n",
       "600099   192.168.100.6        49160  ...     1   Theft\n",
       "\n",
       "[600100 rows x 14 columns]"
      ]
     },
     "execution_count": 3,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "PoVYaeFZtJBd"
   },
   "outputs": [],
   "source": [
    "data['IPV4_SRC_ADDR'] = data.IPV4_SRC_ADDR.apply(lambda x: socket.inet_ntoa(struct.pack('>I', random.randint(0xac100001, 0xac1f0001))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "zs4z58WCtu8k"
   },
   "outputs": [],
   "source": [
    "data['IPV4_SRC_ADDR'] = data.IPV4_SRC_ADDR.apply(str)\n",
    "data['L4_SRC_PORT'] = data.L4_SRC_PORT.apply(str)\n",
    "data['IPV4_DST_ADDR'] = data.IPV4_DST_ADDR.apply(str)\n",
    "data['L4_DST_PORT'] = data.L4_DST_PORT.apply(str)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "id": "9EEwTAK3tle9"
   },
   "outputs": [],
   "source": [
    "data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR'] + ':' + data['L4_SRC_PORT']\n",
    "data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR'] + ':' + data['L4_DST_PORT']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "id": "xbdaHUxOtzd-"
   },
   "outputs": [],
   "source": [
    "data.drop(columns=['L4_SRC_PORT','L4_DST_PORT'],inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 419
    },
    "id": "CN9rLLmr0eeI",
    "outputId": "ccd523c2-0cba-46a4-aef1-434f6a2b741b"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>IPV4_SRC_ADDR</th>\n",
       "      <th>IPV4_DST_ADDR</th>\n",
       "      <th>PROTOCOL</th>\n",
       "      <th>L7_PROTO</th>\n",
       "      <th>IN_BYTES</th>\n",
       "      <th>OUT_BYTES</th>\n",
       "      <th>IN_PKTS</th>\n",
       "      <th>OUT_PKTS</th>\n",
       "      <th>TCP_FLAGS</th>\n",
       "      <th>FLOW_DURATION_MILLISECONDS</th>\n",
       "      <th>Label</th>\n",
       "      <th>Attack</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>172.24.221.25:52670</td>\n",
       "      <td>192.168.100.1:53</td>\n",
       "      <td>17</td>\n",
       "      <td>5.212</td>\n",
       "      <td>71</td>\n",
       "      <td>126</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>4294966</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>172.30.40.30:49160</td>\n",
       "      <td>192.168.100.149:4444</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>217753000</td>\n",
       "      <td>199100</td>\n",
       "      <td>4521</td>\n",
       "      <td>4049</td>\n",
       "      <td>24</td>\n",
       "      <td>4176249</td>\n",
       "      <td>1</td>\n",
       "      <td>Theft</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>172.18.33.9:3456</td>\n",
       "      <td>192.168.100.5:80</td>\n",
       "      <td>17</td>\n",
       "      <td>0.000</td>\n",
       "      <td>8508021</td>\n",
       "      <td>8918372</td>\n",
       "      <td>9086</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>172.28.162.77:80</td>\n",
       "      <td>192.168.100.55:8080</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>8442138</td>\n",
       "      <td>9013406</td>\n",
       "      <td>9086</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>172.16.172.176:80</td>\n",
       "      <td>192.168.100.5:80</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>8374706</td>\n",
       "      <td>0</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600095</th>\n",
       "      <td>172.29.255.125:80</td>\n",
       "      <td>192.168.100.5:80</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>2330065</td>\n",
       "      <td>0</td>\n",
       "      <td>2523</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263037</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600096</th>\n",
       "      <td>172.23.113.241:0</td>\n",
       "      <td>192.168.100.3:0</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1054423</td>\n",
       "      <td>0</td>\n",
       "      <td>1513</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263062</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600097</th>\n",
       "      <td>172.18.235.164:365</td>\n",
       "      <td>192.168.100.3:565</td>\n",
       "      <td>17</td>\n",
       "      <td>0.000</td>\n",
       "      <td>62422</td>\n",
       "      <td>0</td>\n",
       "      <td>1357</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263062</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600098</th>\n",
       "      <td>172.22.128.93:50850</td>\n",
       "      <td>13.54.166.67:8883</td>\n",
       "      <td>6</td>\n",
       "      <td>222.178</td>\n",
       "      <td>11300</td>\n",
       "      <td>1664</td>\n",
       "      <td>32</td>\n",
       "      <td>32</td>\n",
       "      <td>24</td>\n",
       "      <td>4264935</td>\n",
       "      <td>0</td>\n",
       "      <td>Benign</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600099</th>\n",
       "      <td>172.25.237.107:49160</td>\n",
       "      <td>192.168.100.149:4444</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>40102320</td>\n",
       "      <td>37280</td>\n",
       "      <td>763</td>\n",
       "      <td>590</td>\n",
       "      <td>24</td>\n",
       "      <td>4270068</td>\n",
       "      <td>1</td>\n",
       "      <td>Theft</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>600100 rows × 12 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "               IPV4_SRC_ADDR         IPV4_DST_ADDR  ...  Label  Attack\n",
       "0        172.24.221.25:52670      192.168.100.1:53  ...      0  Benign\n",
       "1         172.30.40.30:49160  192.168.100.149:4444  ...      1   Theft\n",
       "2           172.18.33.9:3456      192.168.100.5:80  ...      0  Benign\n",
       "3           172.28.162.77:80   192.168.100.55:8080  ...      0  Benign\n",
       "4          172.16.172.176:80      192.168.100.5:80  ...      0  Benign\n",
       "...                      ...                   ...  ...    ...     ...\n",
       "600095     172.29.255.125:80      192.168.100.5:80  ...      0  Benign\n",
       "600096      172.23.113.241:0       192.168.100.3:0  ...      0  Benign\n",
       "600097    172.18.235.164:365     192.168.100.3:565  ...      0  Benign\n",
       "600098   172.22.128.93:50850     13.54.166.67:8883  ...      0  Benign\n",
       "600099  172.25.237.107:49160  192.168.100.149:4444  ...      1   Theft\n",
       "\n",
       "[600100 rows x 12 columns]"
      ]
     },
     "execution_count": 8,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "id": "C_WU15ngvnBM"
   },
   "outputs": [],
   "source": [
    "data.drop(columns=['Label'],inplace = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "Q0d3nbdiv37j"
   },
   "outputs": [],
   "source": [
    "data.rename(columns={\"Attack\": \"label\"},inplace = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "yjS-hTKDzI29"
   },
   "outputs": [],
   "source": [
    "le = LabelEncoder()\n",
    "le.fit_transform(data.label.values)\n",
    "data['label'] = le.transform(data['label'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "SVgjPVfg03XG"
   },
   "outputs": [],
   "source": [
    "label = data.label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "id": "ADl2Fj7H08Rr"
   },
   "outputs": [],
   "source": [
    "data.drop(columns=['label'],inplace = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "id": "qhsZMD3uwLk7"
   },
   "outputs": [],
   "source": [
    "scaler = StandardScaler()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "id": "aukoVdNf2zcp"
   },
   "outputs": [],
   "source": [
    "data =  pd.concat([data, label], axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 419
    },
    "id": "IP-ZEZW4nxSm",
    "outputId": "d3f123dd-51b2-447d-958b-05c3109bb362"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>IPV4_SRC_ADDR</th>\n",
       "      <th>IPV4_DST_ADDR</th>\n",
       "      <th>PROTOCOL</th>\n",
       "      <th>L7_PROTO</th>\n",
       "      <th>IN_BYTES</th>\n",
       "      <th>OUT_BYTES</th>\n",
       "      <th>IN_PKTS</th>\n",
       "      <th>OUT_PKTS</th>\n",
       "      <th>TCP_FLAGS</th>\n",
       "      <th>FLOW_DURATION_MILLISECONDS</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>172.24.221.25:52670</td>\n",
       "      <td>192.168.100.1:53</td>\n",
       "      <td>17</td>\n",
       "      <td>5.212</td>\n",
       "      <td>71</td>\n",
       "      <td>126</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>4294966</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>172.30.40.30:49160</td>\n",
       "      <td>192.168.100.149:4444</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>217753000</td>\n",
       "      <td>199100</td>\n",
       "      <td>4521</td>\n",
       "      <td>4049</td>\n",
       "      <td>24</td>\n",
       "      <td>4176249</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>172.18.33.9:3456</td>\n",
       "      <td>192.168.100.5:80</td>\n",
       "      <td>17</td>\n",
       "      <td>0.000</td>\n",
       "      <td>8508021</td>\n",
       "      <td>8918372</td>\n",
       "      <td>9086</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>172.28.162.77:80</td>\n",
       "      <td>192.168.100.55:8080</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>8442138</td>\n",
       "      <td>9013406</td>\n",
       "      <td>9086</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>172.16.172.176:80</td>\n",
       "      <td>192.168.100.5:80</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>8374706</td>\n",
       "      <td>0</td>\n",
       "      <td>9086</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4175916</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600095</th>\n",
       "      <td>172.29.255.125:80</td>\n",
       "      <td>192.168.100.5:80</td>\n",
       "      <td>6</td>\n",
       "      <td>7.000</td>\n",
       "      <td>2330065</td>\n",
       "      <td>0</td>\n",
       "      <td>2523</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263037</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600096</th>\n",
       "      <td>172.23.113.241:0</td>\n",
       "      <td>192.168.100.3:0</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>1054423</td>\n",
       "      <td>0</td>\n",
       "      <td>1513</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263062</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600097</th>\n",
       "      <td>172.18.235.164:365</td>\n",
       "      <td>192.168.100.3:565</td>\n",
       "      <td>17</td>\n",
       "      <td>0.000</td>\n",
       "      <td>62422</td>\n",
       "      <td>0</td>\n",
       "      <td>1357</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4263062</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600098</th>\n",
       "      <td>172.22.128.93:50850</td>\n",
       "      <td>13.54.166.67:8883</td>\n",
       "      <td>6</td>\n",
       "      <td>222.178</td>\n",
       "      <td>11300</td>\n",
       "      <td>1664</td>\n",
       "      <td>32</td>\n",
       "      <td>32</td>\n",
       "      <td>24</td>\n",
       "      <td>4264935</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600099</th>\n",
       "      <td>172.25.237.107:49160</td>\n",
       "      <td>192.168.100.149:4444</td>\n",
       "      <td>6</td>\n",
       "      <td>0.000</td>\n",
       "      <td>40102320</td>\n",
       "      <td>37280</td>\n",
       "      <td>763</td>\n",
       "      <td>590</td>\n",
       "      <td>24</td>\n",
       "      <td>4270068</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>600100 rows × 11 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "               IPV4_SRC_ADDR  ... label\n",
       "0        172.24.221.25:52670  ...     0\n",
       "1         172.30.40.30:49160  ...     4\n",
       "2           172.18.33.9:3456  ...     0\n",
       "3           172.28.162.77:80  ...     0\n",
       "4          172.16.172.176:80  ...     0\n",
       "...                      ...  ...   ...\n",
       "600095     172.29.255.125:80  ...     0\n",
       "600096      172.23.113.241:0  ...     0\n",
       "600097    172.18.235.164:365  ...     0\n",
       "600098   172.22.128.93:50850  ...     0\n",
       "600099  172.25.237.107:49160  ...     4\n",
       "\n",
       "[600100 rows x 11 columns]"
      ]
     },
     "execution_count": 16,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "id": "PUa4uJbewQc7"
   },
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "     data, label, test_size=0.3, random_state=123,stratify= label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "z3DrIWDHqNxp",
    "outputId": "e2777f43-f37e-4596-eb7b-21186d3bf389"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.6/dist-packages/category_encoders/utils.py:21: FutureWarning: is_categorical is deprecated and will be removed in a future version.  Use is_categorical_dtype instead\n",
      "  elif pd.api.types.is_categorical(cols):\n"
     ]
    }
   ],
   "source": [
    "encoder = ce.TargetEncoder(cols=['TCP_FLAGS','L7_PROTO','PROTOCOL'])\n",
    "encoder.fit(X_train, y_train)\n",
    "X_train = encoder.transform(X_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "id": "EDKYHCbcqN81"
   },
   "outputs": [],
   "source": [
    "cols_to_norm = list(set(list(X_train.iloc[:, 2:].columns ))  - set(list(['label'])) )\n",
    "X_train[cols_to_norm] = scaler.fit_transform(X_train[cols_to_norm])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "id": "ek535MkWwUHN"
   },
   "outputs": [],
   "source": [
    "X_train['h'] = X_train[ cols_to_norm ].values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 711
    },
    "id": "v4mfPB0X9rRX",
    "outputId": "29a8752f-28cd-49b4-c4c1-15e0d58d4a6a"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>IPV4_SRC_ADDR</th>\n",
       "      <th>IPV4_DST_ADDR</th>\n",
       "      <th>PROTOCOL</th>\n",
       "      <th>L7_PROTO</th>\n",
       "      <th>IN_BYTES</th>\n",
       "      <th>OUT_BYTES</th>\n",
       "      <th>IN_PKTS</th>\n",
       "      <th>OUT_PKTS</th>\n",
       "      <th>TCP_FLAGS</th>\n",
       "      <th>FLOW_DURATION_MILLISECONDS</th>\n",
       "      <th>label</th>\n",
       "      <th>h</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>592389</th>\n",
       "      <td>172.22.161.1:57470</td>\n",
       "      <td>192.168.100.3:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.010775</td>\n",
       "      <td>-0.007610</td>\n",
       "      <td>0.002649</td>\n",
       "      <td>-0.008687</td>\n",
       "      <td>-1.419793</td>\n",
       "      <td>-2.082482</td>\n",
       "      <td>3</td>\n",
       "      <td>[-0.008687378732836464, -0.010775447906154435,...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>541914</th>\n",
       "      <td>172.20.109.96:53426</td>\n",
       "      <td>192.168.100.3:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.015998</td>\n",
       "      <td>-0.007551</td>\n",
       "      <td>-0.021496</td>\n",
       "      <td>-0.003471</td>\n",
       "      <td>-1.557296</td>\n",
       "      <td>-2.082482</td>\n",
       "      <td>1</td>\n",
       "      <td>[-0.003471109481788205, -0.015997749788891628,...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>393332</th>\n",
       "      <td>172.23.80.235:60855</td>\n",
       "      <td>192.168.100.6:9080</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "      <td>[-0.02433618648598124, -0.01743253012037605, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>180488</th>\n",
       "      <td>172.29.38.38:14323</td>\n",
       "      <td>192.168.100.3:12139</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017440</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "      <td>[-0.02433618648598124, -0.017439993217028764, ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>207769</th>\n",
       "      <td>172.17.187.99:40317</td>\n",
       "      <td>192.168.100.5:5357</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "      <td>[-0.02433618648598124, -0.01743253012037605, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>96131</th>\n",
       "      <td>172.28.236.237:57963</td>\n",
       "      <td>192.168.100.5:1027</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496290</td>\n",
       "      <td>3</td>\n",
       "      <td>[-0.02433618648598124, -0.01743253012037605, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>583684</th>\n",
       "      <td>172.26.229.7:54248</td>\n",
       "      <td>192.168.100.3:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.016132</td>\n",
       "      <td>-0.007551</td>\n",
       "      <td>-0.021496</td>\n",
       "      <td>-0.003471</td>\n",
       "      <td>-1.557296</td>\n",
       "      <td>-2.082482</td>\n",
       "      <td>1</td>\n",
       "      <td>[-0.003471109481788205, -0.016132085528640493,...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>599529</th>\n",
       "      <td>172.25.187.120:43797</td>\n",
       "      <td>192.168.100.150:4433</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017403</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>4</td>\n",
       "      <td>[-0.02433618648598124, -0.01740267773376519, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>352726</th>\n",
       "      <td>172.19.103.146:33197</td>\n",
       "      <td>192.168.100.5:90</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496289</td>\n",
       "      <td>3</td>\n",
       "      <td>[-0.02433618648598124, -0.01743253012037605, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>566386</th>\n",
       "      <td>172.28.138.12:48166</td>\n",
       "      <td>192.168.100.3:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.017306</td>\n",
       "      <td>-0.008424</td>\n",
       "      <td>-0.041617</td>\n",
       "      <td>-0.029552</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>-1.679595</td>\n",
       "      <td>1</td>\n",
       "      <td>[-0.029552455737029498, -0.017305657477279898,...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>420070 rows × 12 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "               IPV4_SRC_ADDR  ...                                                  h\n",
       "592389    172.22.161.1:57470  ...  [-0.008687378732836464, -0.010775447906154435,...\n",
       "541914   172.20.109.96:53426  ...  [-0.003471109481788205, -0.015997749788891628,...\n",
       "393332   172.23.80.235:60855  ...  [-0.02433618648598124, -0.01743253012037605, 0...\n",
       "180488    172.29.38.38:14323  ...  [-0.02433618648598124, -0.017439993217028764, ...\n",
       "207769   172.17.187.99:40317  ...  [-0.02433618648598124, -0.01743253012037605, 0...\n",
       "...                      ...  ...                                                ...\n",
       "96131   172.28.236.237:57963  ...  [-0.02433618648598124, -0.01743253012037605, 0...\n",
       "583684    172.26.229.7:54248  ...  [-0.003471109481788205, -0.016132085528640493,...\n",
       "599529  172.25.187.120:43797  ...  [-0.02433618648598124, -0.01740267773376519, 0...\n",
       "352726  172.19.103.146:33197  ...  [-0.02433618648598124, -0.01743253012037605, 0...\n",
       "566386   172.28.138.12:48166  ...  [-0.029552455737029498, -0.017305657477279898,...\n",
       "\n",
       "[420070 rows x 12 columns]"
      ]
     },
     "execution_count": 21,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "id": "OIrcNfMSwa0j"
   },
   "outputs": [],
   "source": [
    "G = nx.from_pandas_edgelist(X_train, \"IPV4_SRC_ADDR\", \"IPV4_DST_ADDR\", ['h','label'],create_using=nx.MultiGraph())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "QluLSxbiwn7M"
   },
   "outputs": [],
   "source": [
    "G = G.to_directed()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "id": "2zClkKEzwrVb"
   },
   "outputs": [],
   "source": [
    "G = from_networkx(G,edge_attrs=['h','label'] )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "id": "9jlBYgE8wsW7"
   },
   "outputs": [],
   "source": [
    "# Eq1\n",
    "G.ndata['h'] = th.ones(G.num_nodes(), G.edata['h'].shape[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "id": "E7Vc6IELwuJr"
   },
   "outputs": [],
   "source": [
    "G.edata['train_mask'] = th.ones(len(G.edata['h']), dtype=th.bool)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "BIx7-W6s46Ju",
    "outputId": "234c56a1-9958-4e82-e244-b2a41dcf2855"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True,  ..., True, True, True])"
      ]
     },
     "execution_count": 27,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "G.edata['train_mask'] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "id": "DzDap1MR5e95"
   },
   "outputs": [],
   "source": [
    "def compute_accuracy(pred, labels):\n",
    "    return (pred.argmax(1) == labels).float().mean().item()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "id": "5VzTQxAR5HoT"
   },
   "outputs": [],
   "source": [
    "class SAGELayer(nn.Module):\n",
    "    def __init__(self, ndim_in, edims, ndim_out, activation):\n",
    "        super(SAGELayer, self).__init__()\n",
    "        ### force to outut fix dimensions\n",
    "        self.W_msg = nn.Linear(ndim_in + edims, ndim_out)\n",
    "        ### apply weight\n",
    "        self.W_apply = nn.Linear(ndim_in + ndim_out, ndim_out)\n",
    "        self.activation = activation\n",
    "\n",
    "    def message_func(self, edges):\n",
    "        return {'m': self.W_msg(th.cat([edges.src['h'], edges.data['h']], 2))}\n",
    "\n",
    "    def forward(self, g_dgl, nfeats, efeats):\n",
    "        with g_dgl.local_scope():\n",
    "            g = g_dgl\n",
    "            g.ndata['h'] = nfeats\n",
    "            g.edata['h'] = efeats\n",
    "            # Eq4\n",
    "            g.update_all(self.message_func, fn.mean('m', 'h_neigh'))\n",
    "            # Eq5          \n",
    "            g.ndata['h'] = F.relu(self.W_apply(th.cat([g.ndata['h'], g.ndata['h_neigh']], 2)))\n",
    "            return g.ndata['h']\n",
    "\n",
    "\n",
    "class SAGE(nn.Module):\n",
    "    def __init__(self, ndim_in, ndim_out, edim, activation, dropout):\n",
    "        super(SAGE, self).__init__()\n",
    "        self.layers = nn.ModuleList()\n",
    "        self.layers.append(SAGELayer(ndim_in, edim, 128, activation))\n",
    "        self.layers.append(SAGELayer(128, edim, ndim_out, activation))\n",
    "        self.dropout = nn.Dropout(p=dropout)\n",
    "\n",
    "    def forward(self, g, nfeats, efeats):\n",
    "        for i, layer in enumerate(self.layers):\n",
    "            if i != 0:\n",
    "                nfeats = self.dropout(nfeats)\n",
    "            nfeats = layer(g, nfeats, efeats)\n",
    "        return nfeats.sum(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "id": "hrLYvze5wwMi"
   },
   "outputs": [],
   "source": [
    "class MLPPredictor(nn.Module):\n",
    "    def __init__(self, in_features, out_classes):\n",
    "        super().__init__()\n",
    "        self.W = nn.Linear(in_features * 2, out_classes)\n",
    "\n",
    "    def apply_edges(self, edges):\n",
    "        h_u = edges.src['h']\n",
    "        h_v = edges.dst['h']\n",
    "        score = self.W(th.cat([h_u, h_v], 1))\n",
    "        return {'score': score}\n",
    "\n",
    "    def forward(self, graph, h):\n",
    "        with graph.local_scope():\n",
    "            graph.ndata['h'] = h\n",
    "            graph.apply_edges(self.apply_edges)\n",
    "            return graph.edata['score']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "id": "GPLg-kCcwxLa"
   },
   "outputs": [],
   "source": [
    "G.ndata['h'] = th.reshape(G.ndata['h'], (G.ndata['h'].shape[0], 1,G.ndata['h'].shape[1]))\n",
    "G.edata['h'] = th.reshape(G.edata['h'], (G.edata['h'].shape[0], 1,G.edata['h'].shape[1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "id": "SwdZs785w1dT"
   },
   "outputs": [],
   "source": [
    "class Model(nn.Module):\n",
    "    def __init__(self, ndim_in, ndim_out, edim, activation, dropout):\n",
    "        super().__init__()\n",
    "        self.gnn = SAGE(ndim_in, ndim_out, edim, activation, dropout)\n",
    "        self.pred = MLPPredictor(ndim_out, 5)\n",
    "    def forward(self, g, nfeats, efeats):\n",
    "        h = self.gnn(g, nfeats, efeats)\n",
    "        return self.pred(g, h)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "id": "BEw7J1Z45R62"
   },
   "outputs": [],
   "source": [
    "from sklearn.utils import class_weight\n",
    "class_weights = class_weight.compute_class_weight('balanced',\n",
    "                                                 np.unique(G.edata['label'].cpu().numpy()),\n",
    "                                                 G.edata['label'].cpu().numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "id": "Cti0vAFYw3A0"
   },
   "outputs": [],
   "source": [
    "class_weights = th.FloatTensor(class_weights).cuda()\n",
    "criterion = nn.CrossEntropyLoss(weight = class_weights)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Rj3DHIZmw4IM",
    "outputId": "25d6e453-935e-4132-e67b-f6dbc46c699a"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "device(type='cuda', index=0)"
      ]
     },
     "execution_count": 35,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "G = G.to('cuda:0')\n",
    "G.device"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "qdlVG3JOw5Qj",
    "outputId": "48880507-da3a-41d5-f470-b594953d822c"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "device(type='cuda', index=0)"
      ]
     },
     "execution_count": 36,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "G.ndata['h'].device\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "dvt3pnXmw6U7",
    "outputId": "9f97f898-6d60-4295-dac3-16efa108353c"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "device(type='cuda', index=0)"
      ]
     },
     "execution_count": 37,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "G.edata['h'].device\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "-_eTiHzWw8Cz",
    "outputId": "a9129648-590f-433f-99e1-f7cf871283d7"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training acc: 0.7604886889457703\n",
      "Training acc: 0.7630763649940491\n",
      "Training acc: 0.7629752159118652\n",
      "Training acc: 0.7625324130058289\n",
      "Training acc: 0.7474111318588257\n",
      "Training acc: 0.7555240392684937\n",
      "Training acc: 0.7655866742134094\n",
      "Training acc: 0.7669566869735718\n",
      "Training acc: 0.764086902141571\n",
      "Training acc: 0.7449960708618164\n",
      "Training acc: 0.7680802941322327\n",
      "Training acc: 0.7622729539871216\n",
      "Training acc: 0.7510450482368469\n",
      "Training acc: 0.7672958970069885\n",
      "Training acc: 0.7625240683555603\n",
      "Training acc: 0.7663900852203369\n",
      "Training acc: 0.7658271193504333\n",
      "Training acc: 0.758365273475647\n",
      "Training acc: 0.7553383708000183\n",
      "Training acc: 0.7583866715431213\n",
      "Training acc: 0.7681624293327332\n",
      "Training acc: 0.7402635216712952\n",
      "Training acc: 0.770497739315033\n",
      "Training acc: 0.7478277087211609\n",
      "Training acc: 0.7465077042579651\n",
      "Training acc: 0.7545242309570312\n",
      "Training acc: 0.7622788548469543\n",
      "Training acc: 0.7641035914421082\n",
      "Training acc: 0.7617313265800476\n",
      "Training acc: 0.7135024666786194\n",
      "Training acc: 0.6975337266921997\n",
      "Training acc: 0.743584394454956\n",
      "Training acc: 0.7351858019828796\n",
      "Training acc: 0.7509081363677979\n",
      "Training acc: 0.7662293910980225\n",
      "Training acc: 0.7644630670547485\n",
      "Training acc: 0.7783333659172058\n",
      "Training acc: 0.7794188857078552\n",
      "Training acc: 0.7470885515213013\n",
      "Training acc: 0.7760372757911682\n",
      "Training acc: 0.7278262972831726\n",
      "Training acc: 0.6634441614151001\n",
      "Training acc: 0.7783988118171692\n",
      "Training acc: 0.7747482061386108\n",
      "Training acc: 0.7487632632255554\n",
      "Training acc: 0.7725141048431396\n",
      "Training acc: 0.7573392391204834\n",
      "Training acc: 0.7558466196060181\n",
      "Training acc: 0.7607719898223877\n",
      "Training acc: 0.7708083987236023\n",
      "Training acc: 0.7760908603668213\n",
      "Training acc: 0.7746327519416809\n",
      "Training acc: 0.7804449200630188\n",
      "Training acc: 0.7635298371315002\n",
      "Training acc: 0.7794129252433777\n",
      "Training acc: 0.7657199501991272\n",
      "Training acc: 0.7758099436759949\n",
      "Training acc: 0.7808020114898682\n",
      "Training acc: 0.7788273096084595\n",
      "Training acc: 0.7717106342315674\n",
      "Training acc: 0.7768204808235168\n",
      "Training acc: 0.7808698415756226\n",
      "Training acc: 0.7805413007736206\n",
      "Training acc: 0.7821577191352844\n",
      "Training acc: 0.7807865142822266\n",
      "Training acc: 0.783061146736145\n",
      "Training acc: 0.7843394875526428\n",
      "Training acc: 0.7842049598693848\n",
      "Training acc: 0.7844228148460388\n",
      "Training acc: 0.7642749547958374\n",
      "Training acc: 0.7444033026695251\n",
      "Training acc: 0.7801163792610168\n",
      "Training acc: 0.7792201042175293\n",
      "Training acc: 0.7795700430870056\n",
      "Training acc: 0.7577593922615051\n",
      "Training acc: 0.7768431305885315\n",
      "Training acc: 0.7813816666603088\n",
      "Training acc: 0.7780929207801819\n",
      "Training acc: 0.7811007499694824\n"
     ]
    }
   ],
   "source": [
    "node_features = G.ndata['h']\n",
    "edge_features = G.edata['h']\n",
    "\n",
    "edge_label = G.edata['label']\n",
    "train_mask = G.edata['train_mask']\n",
    "\n",
    "model = Model(G.ndata['h'].shape[2], 128, G.ndata['h'].shape[2], F.relu, 0.2).cuda()\n",
    "opt = th.optim.Adam(model.parameters())\n",
    "\n",
    "for epoch in range(1,8000):\n",
    "    pred = model(G, node_features,edge_features).cuda()\n",
    "    loss = criterion(pred[train_mask] ,edge_label[train_mask])\n",
    "    opt.zero_grad()\n",
    "    loss.backward()\n",
    "    opt.step()\n",
    "    if epoch % 100 == 0:\n",
    "      print('Training acc:', compute_accuracy(pred[train_mask], edge_label[train_mask]))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "id": "p7gYo6lVtHCN"
   },
   "outputs": [],
   "source": [
    "X_test = encoder.transform(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "id": "OUGIEbMFtSnf"
   },
   "outputs": [],
   "source": [
    "X_test[cols_to_norm] = scaler.transform(X_test[cols_to_norm])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 439
    },
    "id": "VlyqlEqjtb9s",
    "outputId": "6b637a23-7f60-4810-9348-38c50d09d30c"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>IPV4_SRC_ADDR</th>\n",
       "      <th>IPV4_DST_ADDR</th>\n",
       "      <th>PROTOCOL</th>\n",
       "      <th>L7_PROTO</th>\n",
       "      <th>IN_BYTES</th>\n",
       "      <th>OUT_BYTES</th>\n",
       "      <th>IN_PKTS</th>\n",
       "      <th>OUT_PKTS</th>\n",
       "      <th>TCP_FLAGS</th>\n",
       "      <th>FLOW_DURATION_MILLISECONDS</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>508964</th>\n",
       "      <td>172.29.164.251:3851</td>\n",
       "      <td>192.168.100.148:57874</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017440</td>\n",
       "      <td>-0.008374</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>550351</th>\n",
       "      <td>172.27.194.211:59388</td>\n",
       "      <td>192.168.100.3:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.015694</td>\n",
       "      <td>-0.007551</td>\n",
       "      <td>-0.021496</td>\n",
       "      <td>-0.003471</td>\n",
       "      <td>-1.557296</td>\n",
       "      <td>-2.082482</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>126326</th>\n",
       "      <td>172.30.164.19:14903</td>\n",
       "      <td>192.168.100.3:12625</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017440</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75198</th>\n",
       "      <td>172.23.94.131:33223</td>\n",
       "      <td>192.168.100.5:2383</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496290</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>459608</th>\n",
       "      <td>172.22.61.164:53308</td>\n",
       "      <td>192.168.100.3:3306</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.016705</td>\n",
       "      <td>-0.007860</td>\n",
       "      <td>-0.021496</td>\n",
       "      <td>0.001745</td>\n",
       "      <td>-1.378847</td>\n",
       "      <td>0.496174</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>219108</th>\n",
       "      <td>172.18.51.155:45576</td>\n",
       "      <td>192.168.100.3:1114</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>527997</th>\n",
       "      <td>172.22.242.126:40850</td>\n",
       "      <td>192.168.100.3:60161</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38363</th>\n",
       "      <td>172.22.50.60:57088</td>\n",
       "      <td>192.168.100.7:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.016455</td>\n",
       "      <td>-0.006905</td>\n",
       "      <td>-0.029544</td>\n",
       "      <td>-0.008687</td>\n",
       "      <td>-1.378847</td>\n",
       "      <td>0.486699</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>159958</th>\n",
       "      <td>172.25.87.154:39747</td>\n",
       "      <td>192.168.100.7:2251</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>0.564662</td>\n",
       "      <td>-0.017433</td>\n",
       "      <td>-0.008378</td>\n",
       "      <td>-0.045641</td>\n",
       "      <td>-0.024336</td>\n",
       "      <td>0.675890</td>\n",
       "      <td>0.496292</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>541341</th>\n",
       "      <td>172.30.219.164:53054</td>\n",
       "      <td>192.168.100.3:80</td>\n",
       "      <td>0.256954</td>\n",
       "      <td>-1.663308</td>\n",
       "      <td>-0.016222</td>\n",
       "      <td>-0.007551</td>\n",
       "      <td>-0.021496</td>\n",
       "      <td>-0.003471</td>\n",
       "      <td>-1.557296</td>\n",
       "      <td>-2.082482</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>180030 rows × 11 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "               IPV4_SRC_ADDR  ... label\n",
       "508964   172.29.164.251:3851  ...     3\n",
       "550351  172.27.194.211:59388  ...     3\n",
       "126326   172.30.164.19:14903  ...     3\n",
       "75198    172.23.94.131:33223  ...     3\n",
       "459608   172.22.61.164:53308  ...     3\n",
       "...                      ...  ...   ...\n",
       "219108   172.18.51.155:45576  ...     3\n",
       "527997  172.22.242.126:40850  ...     3\n",
       "38363     172.22.50.60:57088  ...     1\n",
       "159958   172.25.87.154:39747  ...     3\n",
       "541341  172.30.219.164:53054  ...     2\n",
       "\n",
       "[180030 rows x 11 columns]"
      ]
     },
     "execution_count": 41,
     "metadata": {
      "tags": []
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "id": "q5CMxVe5xIDb"
   },
   "outputs": [],
   "source": [
    "X_test['h'] = X_test[ cols_to_norm ].values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "id": "VsAmtLAbxN_6"
   },
   "outputs": [],
   "source": [
    "G_test = nx.from_pandas_edgelist(X_test, \"IPV4_SRC_ADDR\", \"IPV4_DST_ADDR\", ['h','label'],create_using=nx.MultiGraph())\n",
    "G_test = G_test.to_directed()\n",
    "G_test = from_networkx(G_test,edge_attrs=['h','label'] )\n",
    "actual = G_test.edata.pop('label')\n",
    "G_test.ndata['feature'] = th.ones(G_test.num_nodes(), G.ndata['h'].shape[2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "id": "Eeux6JIxxQtC"
   },
   "outputs": [],
   "source": [
    "G_test.ndata['feature'] = th.reshape(G_test.ndata['feature'], (G_test.ndata['feature'].shape[0], 1, G_test.ndata['feature'].shape[1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "id": "PBETQI3YxYay"
   },
   "outputs": [],
   "source": [
    "G_test.edata['h'] = th.reshape(G_test.edata['h'], (G_test.edata['h'].shape[0], 1, G_test.edata['h'].shape[1]))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "id": "qlTOyVN6xZZB"
   },
   "outputs": [],
   "source": [
    "G_test = G_test.to('cuda:0')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "id": "QyugNIt9xac6"
   },
   "outputs": [],
   "source": [
    "import timeit\n",
    "start_time = timeit.default_timer()\n",
    "node_features_test = G_test.ndata['feature']\n",
    "edge_features_test = G_test.edata['h']\n",
    "test_pred = model(G_test, node_features_test, edge_features_test).cuda()\n",
    "elapsed = timeit.default_timer() - start_time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "KecCvilSxcFK",
    "outputId": "8e974877-889d-43a1-e5c7-06e1e731e1d0"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.02484787100001995 seconds\n"
     ]
    }
   ],
   "source": [
    "print(str(elapsed) + ' seconds')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "id": "BNQLnLoAxdST"
   },
   "outputs": [],
   "source": [
    "test_pred = test_pred.argmax(1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "id": "9dtggXXsxevx"
   },
   "outputs": [],
   "source": [
    "test_pred = th.Tensor.cpu(test_pred).detach().numpy()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "id": "5TGb_KWRxfzS"
   },
   "outputs": [],
   "source": [
    "actual = le.inverse_transform(actual)\n",
    "test_pred = le.inverse_transform(test_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "id": "n7z7tHTPxhBC"
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import plot_confusion_matrix\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "id": "uMRairwzxiBC"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "\n",
    "def plot_confusion_matrix(cm,\n",
    "                          target_names,\n",
    "                          title='Confusion matrix',\n",
    "                          cmap=None,\n",
    "                          normalize=True):\n",
    "    \n",
    "    import matplotlib.pyplot as plt\n",
    "    import numpy as np\n",
    "    import itertools\n",
    "\n",
    "    accuracy = np.trace(cm) / float(np.sum(cm))\n",
    "    misclass = 1 - accuracy\n",
    "\n",
    "    if cmap is None:\n",
    "        cmap = plt.get_cmap('Blues')\n",
    "\n",
    "    plt.figure(figsize=(12, 12))\n",
    "    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n",
    "    plt.title(title)\n",
    "    plt.colorbar()\n",
    "\n",
    "    if target_names is not None:\n",
    "        tick_marks = np.arange(len(target_names))\n",
    "        plt.xticks(tick_marks, target_names, rotation=45)\n",
    "        plt.yticks(tick_marks, target_names)\n",
    "\n",
    "    if normalize:\n",
    "        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
    "\n",
    "\n",
    "    thresh = cm.max() / 1.5 if normalize else cm.max() / 2\n",
    "    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n",
    "        if normalize:\n",
    "            plt.text(j, i, \"{:0.4f}\".format(cm[i, j]),\n",
    "                     horizontalalignment=\"center\",\n",
    "                     color=\"white\" if cm[i, j] > thresh else \"black\")\n",
    "        else:\n",
    "            plt.text(j, i, \"{:,}\".format(cm[i, j]),\n",
    "                     horizontalalignment=\"center\",\n",
    "                     color=\"white\" if cm[i, j] > thresh else \"black\")\n",
    "\n",
    "\n",
    "    plt.tight_layout()\n",
    "    plt.ylabel('True label')\n",
    "    plt.xlabel('Predicted label\\naccuracy={:0.4f}; misclass={:0.4f}'.format(accuracy, misclass))\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 718
    },
    "id": "KNCkVWyqxjaR",
    "outputId": "3af8ef73-a011-49a7-9335-52ba77ea7dd4"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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j19/9RV069SGzTu3pd/B+zNjxgwAjjniMLbatD1bbtKOg/fvzdSpU6vnolTu2CP70Xr9xmy1abvysQ/ff49dtt+Crbu258Dee/DTlCmVHv/TlCm0b7kep5xwTPnYow/dz9Zd27NN1w7su9cufPdd7v+PH374nt49e9C1fUt69+zB5Mk/VN+FaZFU9ll91hmn0andxnTp0JZdenRnwoQJRY5Uv9WsWbPYpGM79tx9FwBeevEFNu3Uni4d2rLNlt34fPTo8n0fevCB8v8HDjpgv2KFLFW7hVk6/AzgP/nb1sBFwG7VHJeWQnXq1OGCiy7lnfc+4uUhb3LD9dfw8UcfcerJ/+LU087greEjOe3Mszn15H8VO1TNo0/fg7jv0QHzjY8fN5aXXnyOxms3yTzu008+4rGH72fI2+9y/6MDOPG4vzNr1iwmThjPTddfw3OvvMmrb49k1qxZPPrQ/QCce8GlDH5jBC+/+Q6NG6/NLTdcW63XJui13wHc89CTc40df/ThnHLGubz0+gh67LI71151WaXHX3jemWzStVv547KyMk476XgeenIQL74+nJatNuK2G68D4OrLL6bbltvw+oiP6LblNlx9+cXVc1FaZJV9Vh97/AkMfec93ho+kh477cL5555d7FD1G1191ZU033DD8sdHH/U3bruzP28NH0nvPvtxwb/PBWD0qFFccuH5vPjya4x490MuvvSKYoUsVbuFqSztDWwL/C+ldDDQBlilWqPSUqlBgwa0a98egJVXXpkWLTZkwoTxRART8n+1/vHHH2nQsGExw1SGrt02Z9VV/zjf+P+d9E/OOOf8Sr9t/JkBT9Jzr94su+yyrNN0XZqu9ydGDMtVDsvKypjx88+UlZXx8/TprNUg9+++cr16AKSUmDHjZ7/JvAA23WxzVl111bnGvvh8FJtutjkAW2y9LU89+Wjmse+OHMGkb79hy623Kx9LKZFSYvq0aaSU+OmnKazZoAEAzz79JL323R+AXvvuz8CnnqiOS9LvUNlndb38exNg+vRpvjdLzLhx4xj4zFMcfMhfyscq/vydMuX///y99Zab+Ovfjiz/XKhfv37hA15a1YBlwZe2pcOrWuBhjp9TSrMjoiwi6gHfAGtXc1xayn01ZgwjR75Dp85duPjSK9h15x04+cR/Mnv2bF565fVih6eF8MyAJ2jQsCGtN2pT6T4TJ46nY6cu5Y8bNmzExIkT6NRlU444+ljatlyP5Zdbnq223Y6tt92+fL+/H34oLwwayAYtNuSsf1t5KIbmLVoy8Kkn6LHL7jz52MNMGD9uvn1mz57NWaeeyNU33sarg18sH69bty4XXvYfttmsAyussCLrrrc+519yFQDffvMNa66VS5zqr7kW337zTWEuSIuk4mc1wBmnnUr/u+9klVVWYeBzLxU5Ov0WJxz/D847/yKmTv2pfOzaG25mj912Yrnll6devXq8PORNAEaN+gyArbfYjFmzZvF/p59J9x12LErcUnVbmMrSsIj4A3ATuRXyRgBvVGtUJSoiZkXEyIj4MCLejYjjI6LK1zgiVoiI/hHxfkR8EBFDImKlQsVcE02dOpV9e+3FxZdeQb169bjxhuu46JLLGf3lWC665HL+1u/QYoeoBZg+fTpXXHoBJ5165iIdP/mHHxj41JMMf38U74/6L9OnTefB+/qXb//P9bfw/qj/skHzFjz28AOLKWr9FpddfQO333ID3bfchGlTp7JM3WXm2+f2m69n2+470LBR47nGZ86cyR233MBzr7zFyE/G0LJ1a6667KL5jo8IqxM12Lyf1QBnnXMeo78cS599+3L9tVcXOUItrKefGkD9NerTvkOHucb/c+XlPPrE03w+ZhwHHHQwJ/7zOABmlZUxevQoBr0wmDvvvpcjDj+MyZMnFyN0qdotsLKUUjoif/f6iBgI1EspvVe9YZWsn1NKbQEioj5wD1APOKOKY44Bvk4pbZQ/rjkws7oDralmzpzJvr32ove+fem5x54A9L/rDi69PDeBeK+99+GIv/6lqlOoBhjz5ef8d8wYtuqa+8E7Yfw4tt28M88Ofp0111yrfL8GDRoxftz/r0hMmDCeBg0a8vLgF2iyTlNWX2MNAHberSdD33qDffr0Ld+3du3a9NyrN1dfcQn7HfDnwlyYyjXboAX3P5r7yr3PR3/G84OemW+fYUPf4q03XuP2m29k2rSpzJz5KyuuuBI777YHAE3X/RMAu/bcm6uvyFUI16hfn6//N5E112rA1/+bWP7/gGqWrM/qinrv25c9dtuJ0844qwjR6bd64/XXGDDgCQYOfJpfZsxgypQp7LHbznz66Sd07pKrGu69T2923yVXPWrUqDGdOnehbt26NF13XZo124DRo0bRsVOnYl7GUsM/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4OQL7wDgoJ1/zHH79eHQU69h/x3W4YVX32W7wy9hri6defrmX3PNnf35+psxEzzu2b/YjnsffY5djr6M9u3a0mmmDgA8+8rb7PT/LuX8X+08wfHPvvI2P9r1TMaMGcu8c83G49cexx0PD2HMmLG1+YeYAbVt147TzjiblVdehZEjR7JWr56sv8GGLLvscuOPGfryy5x95unc/+C/6dKlC++///742w4/8ii+GD2ay/7U91uP/eTAAXz8SfUboPr+Amjj6PCasrKkZjXPvF1ZcaWVAeg866wsudQyvPvOcH68/oa0a1fk6qv0XI133n5rqh53hW7dWXChRb61PkvnzuOvP/DF558TdvbW1EsvvkDPVVejU6dOtGvXjh+tvQ633XLzt4477eQTOezIo+k400xT9fhDX36JDz54nzV/tPb0CllT6aUXX6BnzybneK1vn+OFFl6EX85WZQAAIABJREFUFVbsRps2E/6KefGF51nzR2vTrl07ZpllFpZfYUUeuO+eWoavJt798DMGvVD87B01+kteGPYu8809OyM//+/4YzrN3JHMBCCBzrN0BGCWmTvy8aej+WaihGa2zjOx1iqLc8XN/wHg62/G8OmoLwB4cdh7vPz6+0zsi/9+PT4x6tih/fjnU/Pp2rUrK6+8ClC8IbX0Msvy9vDhExzz58svZf8DDqJLly4A/PCHPxx/23rr/4TOs367cjRmzBiOP+4X/Pa0M5oxeqm2TJZUM2++8RpDBg9i5R4TVhOu/ftfWG+DjSrv8+V//8sm66/J5huuw9133DpFz3PX7bfw49W7sftOW3POeZd877g15ZZdbnn+8+i/+WjECEaPHs1999zF8OETJsJPP/Ukw4e/yUYbb/qt+7/x+jDWWaMnm260Ho8+0u9bt990w7Vss+32XpCvjirP8VtT9mbHCit24/777mH06NGM+PBD+j38IMPfenP87b896df8aLWV+eUvjuTLL79srpegCgt1nYPuSy9A/yGvAXDSwZvz8l2nsFOfnpxyUVFluviah1hm0Xl59d5TGXD9LznqrBu+ldgsMt+cfPjxKPr+5qf85+pjuPCEXcZXliZn1RUWZuANxzPg+l9y6KnXWFWqoddfe42nn36KVVdbfYL1oS+/zMsvv8RP1l2Ldddeg3vvufs7H+viC89nk003p2vXrs0VrlRzzZYsRcSY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",
      "text/plain": [
       "<Figure size 864x864 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light",
      "tags": []
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "plot_confusion_matrix(cm = confusion_matrix(actual, test_pred), \n",
    "                      normalize    = False,\n",
    "                      target_names = np.unique(actual),\n",
    "                      title        = \"Confusion Matrix\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "rC9-S7j9A48K"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "machine_shape": "hm",
   "name": "Unsw_bot_iot_multiclass_mean_agg.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
